package cc.yiueil.config;

import cc.yiueil.filter.JwtFilter;
import cc.yiueil.handler.CustomAccessDeniedHandler;
import cc.yiueil.handler.CustomAuthenticationEntryPoint;
import cc.yiueil.mapper.UserMapper;
import cc.yiueil.model.entity.RoleEntity;
import cc.yiueil.model.entity.UserEntity;
import cc.yiueil.model.entity.UserPrincipalEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.AuthorizationFilter;

import java.util.List;

@EnableMethodSecurity
@Configuration
public class SecurityConfiguration {

    @Autowired
    UserMapper userMapper;

    @Autowired
    CustomAccessDeniedHandler accessDeniedHandler;

    @Autowired
    CustomAuthenticationEntryPoint customAuthenticationEntryPoint;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(username -> {
            UserEntity userEntity = userMapper.getUserByUsername(username);
            if (userEntity == null) {
                throw new UsernameNotFoundException(username);
            }
            List<RoleEntity> roles = userMapper.getRolesByUserId(userEntity.getId());
            UserPrincipalEntity userPrincipalEntity = new UserPrincipalEntity();
            userPrincipalEntity.setUserEntity(userEntity);
            userPrincipalEntity.setRoles(roles);
            return userPrincipalEntity;
        });
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        return new ProviderManager(daoAuthenticationProvider);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtFilter jwtFilter) throws Exception {
        return http
                .authorizeHttpRequests(authorizeRequests -> authorizeRequests
                        .requestMatchers("/customLogin").permitAll()
                        .anyRequest().authenticated()
                )
                .addFilterBefore(jwtFilter, AuthorizationFilter.class)
                .sessionManagement(AbstractHttpConfigurer::disable)
                .csrf(AbstractHttpConfigurer::disable)
                .formLogin(AbstractHttpConfigurer::disable)
                .logout(AbstractHttpConfigurer::disable)
                .httpBasic(AbstractHttpConfigurer::disable)
                .exceptionHandling(exceptionHandlingConfigurer ->
                        exceptionHandlingConfigurer
                                .accessDeniedHandler(accessDeniedHandler)
                                .authenticationEntryPoint(customAuthenticationEntryPoint)
                )
                .build();
    }
}
